/* 用执行池+等待队列的模式
任务完成时在finally中自动触发下一个任务
保证并发数始终不超过上限 */
class Scheduler {
  constructor(limit) {
    this.limit = limit; // 并发限制
    this.runningCount = 0; // 当前运行任务数
    this.queue = []; // 任务队列
  }

  add(taskFn) {
    return new Promise((resolve, reject) => {
      const runTask = async () => {
        this.runningCount++;
        try {
          await taskFn();
          resolve();
        } catch (err) {
          reject(err);
        } finally {
          this.runningCount--;
          this._next(); // 执行下一个任务
        }
      };

      if (this.runningCount < this.limit) {
        runTask();
      } else {
        this.queue.push(runTask);
      }
    });
  }

  _next() {
    if (this.queue.length > 0 && this.runningCount < this.limit) {
      const nextTask = this.queue.shift();
      nextTask();
    }
  }
}

const scheduler = new Scheduler(2); // 同时最多执行 2 个任务

const timeout = (time) =>
  new Promise((resolve) => {
    setTimeout(resolve, time);
  });

const addTask = (time, name) => {
  scheduler.add(() => timeout(time).then(() => console.log(name)));
};

addTask(1000, "1");
addTask(500, "2");
addTask(300, "3");
addTask(400, "4");

// 期望输出顺序：2、3、1、4
